package ccm.common.dragMouse;

import ccm.common.Utils;
import ccm.component.override.JCheckBox;
import ccm.component.override.JSpinner;

import java.awt.*;
import java.awt.event.*;

public class DragMouse implements MouseListener, MouseMotionListener, MouseWheelListener
{
    /**
     * 鼠标点击和拖动数据
     */
    protected final MouseData mouseData;
    protected final DragMouseListener dragMouseListener;
    /**
     * Y轴缩放输入框
     */
    protected final JSpinner resizeYJSpinner;
    /**
     * 自动Y轴缩放选择
     */
    protected final JCheckBox resizeYJCheckBox;
    /**
     * Y轴偏移输入框
     */
    protected final JSpinner biasYJSpinner;
    /**
     * 自动Y轴偏移选择
     */
    protected final JCheckBox biasYJCheckBox;
    /**
     * X轴缩放输入框
     */
    protected final JSpinner resizeXJSpinner;
    /**
     * 自动Y轴缩放选择
     */
    protected final JCheckBox resizeXJCheckBox;
    /**
     * X轴偏移输入框
     */
    protected final JCheckBox biasXJCheckBox;
    /**
     * 自动X轴偏移选择
     */
    protected final JSpinner biasXJSpinner;
    protected boolean needFresh;

    public DragMouse()
    {
        this(null,null,null,null,null,null,null,null,null);
    }

    public DragMouse(DragMouseListener dragMouseListener,JSpinner resizeYJSpinner,JCheckBox resizeYJCheckBox,JSpinner biasYJSpinner,JCheckBox biasYJCheckBox,JSpinner resizeXJSpinner,JCheckBox resizeXJCheckBox,JSpinner biasXJSpinner,JCheckBox biasXJCheckBox)
    {
        mouseData=new MouseData();
        this.dragMouseListener=dragMouseListener;
        this.resizeYJSpinner=resizeYJSpinner;
        this.resizeYJCheckBox=resizeYJCheckBox;
        this.biasYJSpinner=biasYJSpinner;
        this.biasYJCheckBox=biasYJCheckBox;
        this.resizeXJSpinner=resizeXJSpinner;
        this.resizeXJCheckBox=resizeXJCheckBox;
        this.biasXJSpinner=biasXJSpinner;
        this.biasXJCheckBox=biasXJCheckBox;
    }

    public MouseData getMouseData()
    {
        return mouseData;
    }

    public boolean isNeedFresh()
    {
        return needFresh;
    }

    public void setNeedFresh(boolean needFresh)
    {
        this.needFresh=needFresh;
    }

    /**
     * 设置自动偏移和缩放
     */
    public void updateAutoBiasAndResize()
    {
        enableAutoResizeX(resizeXJCheckBox!=null&&resizeXJCheckBox.isSelected());
        enableAutoResizeY(resizeYJCheckBox!=null&&resizeYJCheckBox.isSelected());
        enableAutoBiasX(biasXJCheckBox!=null&&biasXJCheckBox.isSelected());
        enableAutoBiasY(biasYJCheckBox!=null&&biasYJCheckBox.isSelected());
    }

    /**
     * 设置X轴是否自动缩放
     *
     * @param auto true表示自动偏移
     *             false表示不自动偏移
     */
    public void enableAutoResizeX(boolean auto)
    {
        auto&=resizeXJCheckBox!=null;
        if(resizeXJCheckBox!=null)
        {resizeXJCheckBox.setSelected(auto);}
        if(resizeXJSpinner!=null)
        {resizeXJSpinner.setEnabled(!auto);}
    }

    /**
     * 设置Y轴是否自动缩放
     *
     * @param auto true表示自动缩放
     *             false表示不自动缩放
     */
    public void enableAutoResizeY(boolean auto)
    {
        auto&=resizeYJCheckBox!=null;
        if(resizeYJCheckBox!=null)
        {resizeYJCheckBox.setSelected(auto);}
        if(resizeYJSpinner!=null)
        {resizeYJSpinner.setEnabled(!auto);}
    }

    /**
     * 设置X轴是否自动偏移
     *
     * @param auto true表示自动偏移
     *             false表示不自动偏移
     */
    public void enableAutoBiasX(boolean auto)
    {
        auto&=biasXJCheckBox!=null;
        if(biasXJCheckBox!=null)
        {biasXJCheckBox.setSelected(auto);}
        if(biasXJSpinner!=null)
        {biasXJSpinner.setEnabled(!auto);}
    }

    /**
     * 设置Y轴是否自动偏移
     *
     * @param auto true表示自动偏移
     *             false表示不自动偏移
     */
    public void enableAutoBiasY(boolean auto)
    {
        auto&=biasYJCheckBox!=null;
        if(biasYJCheckBox!=null)
        {biasYJCheckBox.setSelected(auto);}
        if(biasYJSpinner!=null)
        {biasYJSpinner.setEnabled(!auto);}
    }

    public void mouseClicked(MouseEvent e)
    {
        needFresh=true;
        if(e.getButton()==MouseEvent.BUTTON1)
        {
            enableAutoResizeY(true);
            enableAutoBiasY(true);
        }
        if(e.getButton()==MouseEvent.BUTTON3)
        {
            enableAutoBiasX(true);
            if(e.getClickCount()>=2)
            {
                enableAutoResizeY(true);
                enableAutoBiasY(true);
            }
        }
    }

    /**
     * 鼠标按下时准备进入拖动状态
     */
    public void mousePressed(MouseEvent e)
    {
        needFresh=true;
        synchronized(mouseData)
        {
            mouseData.setDragStart(e.getPoint());
            mouseData.setDragBias(new Point(biasXValue(),biasYValue()));
        }
        if(dragMouseListener!=null)
        {dragMouseListener.dragMouseRepaint(e);}
    }

    protected int biasXValue()
    {
        return biasXJSpinner==null?0:(int)biasXJSpinner.getValue();
    }

    protected int biasYValue()
    {
        return biasYJSpinner==null?0:(int)biasYJSpinner.getValue();
    }

    /**
     * 鼠标放开结束拖动
     */
    public void mouseReleased(MouseEvent e)
    {
        needFresh=true;
        synchronized(mouseData)
        {
            mouseData.setPoint(e.getPoint());
        }
        if(dragMouseListener!=null)
        {dragMouseListener.dragMouseRepaint(e);}
    }

    public void mouseEntered(MouseEvent e)
    {

    }

    /**
     * 鼠标离开时结束横纵坐标轴的显示
     */
    public void mouseExited(MouseEvent e)
    {
        needFresh=true;
        synchronized(mouseData)
        {
            mouseData.setPoint(null);
        }
        if(dragMouseListener!=null)
        {dragMouseListener.dragMouseRepaint(e);}
    }

    /**
     * 鼠标拖动时同步更新偏移实现拖动
     */
    public void mouseDragged(MouseEvent e)
    {
        needFresh=true;
        synchronized(mouseData)
        {
            mouseData.setPoint(null);
            enableAutoBiasAndResize(false);
            Utils.setJSpinnerValue(biasXJSpinner,mouseDraggedBiasX(mouseData.getDragBias().x,e.getX(),mouseData.getDragStart().x,resizeXValue()));
            Utils.setJSpinnerValue(biasYJSpinner,mouseDraggedBiasY(mouseData.getDragBias().y,e.getY(),mouseData.getDragStart().y,resizeYValue()));
        }
        if(dragMouseListener!=null)
        {dragMouseListener.dragMouseRepaint(e);}
    }

    /**
     * 设置自动偏移和缩放
     *
     * @param auto true表示全部开启
     *             false表示全部关闭
     */
    public void enableAutoBiasAndResize(boolean auto)
    {
        enableAutoResizeX(auto);
        enableAutoResizeY(auto);
        enableAutoBiasX(auto);
        enableAutoBiasY(auto);
    }

    protected int mouseDraggedBiasX(int bias,int v,int start,float resize)
    {
        return bias-v+start;
    }

    protected float resizeXValue()
    {
        return resizeXJSpinner==null?1:((Number)resizeXJSpinner.getValue()).floatValue();
    }

    protected int mouseDraggedBiasY(int bias,int v,int start,float resize)
    {
        return bias-v+start;
    }

    protected float resizeYValue()
    {
        return resizeYJSpinner==null?1:((Number)resizeYJSpinner.getValue()).floatValue();
    }

    /**
     * 鼠标移动时更新坐标轴
     */
    public void mouseMoved(MouseEvent e)
    {
        needFresh=true;
        synchronized(mouseData)
        {
            mouseData.setPoint(e.getPoint());
        }
        if(dragMouseListener!=null)
        {dragMouseListener.dragMouseRepaint(e);}
    }

    /**
     * 滚轮动作时更新缩放
     */
    public void mouseWheelMoved(MouseWheelEvent e)
    {
        needFresh=true;
        if(e.isControlDown()&&resizeYJSpinner!=null)   //Y轴缩放
        {
            /*
             * Y轴缩放
             * 同步更新Y轴偏移实现顶点缩放
             */
            enableAutoResizeY(false);
            enableAutoBiasY(false);
            float k=(e.getWheelRotation()<0?1.2f:(1.0f/1.2f));
            final float resizeY=resizeYValue();
            Utils.setJSpinnerValue(resizeYJSpinner,(float)(resizeY*k));
            k=resizeYValue()/resizeY;
            if(k!=1&&biasYJSpinner!=null)
            {Utils.setJSpinnerValue(biasYJSpinner,mouseWheelMovedBiasY(k,biasYValue(),e.getY(),resizeY));}
            if(k!=1&&biasXJSpinner!=null&&resizeXJSpinner==null)
            {Utils.setJSpinnerValue(biasXJSpinner,mouseWheelMovedBiasX(k,biasXValue(),e.getX(),resizeY));}
        }
        else if(e.isAltDown()&&resizeXJSpinner!=null&&dragMouseListener!=null)
        {
            /*
             * X轴缩放
             * 同步更新X轴偏移实现顶点缩放
             */
            enableAutoResizeX(false);
            enableAutoBiasX(false);
            float k=(e.getWheelRotation()<0?1.2f:(1.0f/1.2f));
            float resizeX=resizeXValue();
            Utils.setJSpinnerValue(resizeXJSpinner,(float)(resizeX*k));
            k=resizeXValue()/resizeX;
            if(k!=1&&biasXJSpinner!=null)
            {Utils.setJSpinnerValue(biasXJSpinner,mouseWheelMovedBiasX(k,biasXValue(),e.getX(),resizeX));}
            if(k!=1&&biasYJSpinner!=null&&resizeYJSpinner==null)
            {Utils.setJSpinnerValue(biasYJSpinner,mouseWheelMovedBiasY(k,biasYValue(),e.getY(),resizeX));}

        }
        else if(e.isShiftDown()&&biasXJSpinner!=null)
        {
            /*
             * X轴偏移
             */
            enableAutoBiasX(false);
            Utils.setJSpinnerValue(biasXJSpinner,(int)biasXJSpinner.getValue()-(e.getWheelRotation()*20));
        }
        else if(biasYJSpinner!=null)
        {
            /*
             * Y轴偏移
             */
            enableAutoBiasY(false);
            Utils.setJSpinnerValue(biasYJSpinner,(int)biasYJSpinner.getValue()-(e.getWheelRotation()*20));
        }
        if(dragMouseListener!=null)
        {dragMouseListener.dragMouseRepaint(e);}
    }

    protected int mouseWheelMovedBiasY(float k,int bias,int v,float resizeOld)
    {
        return (int)(k*bias-v*(1-k));
    }

    protected int mouseWheelMovedBiasX(float k,int bias,int v,float resizeOld)
    {
        return (int)(k*bias-v*(1-k));
    }
}
